'''
ctypes:提供了一种在 Python 中访问 C 库的方式。它允许你调用动态链接库/共享库中的函数，并在 Python 代码中使用 C 数据类型。
        它主要用于将 Python 与用 C 或其他低级语言编写的库进行交互。
inspect： 是 Python 的一个内置模块。它提供了用于获取有关对象的信息的函数。
        可以使用 inspect 模块来检查模块、类、函数、方法、属性等的定义和结构，以及获取它们的文档字符串、源代码和其他元数据。
        这个模块常用于编写调试工具、自动化测试和代码分析工具。
'''

import ctypes
import inspect


def _async_raise(tid,exc_type):
    '''
    用来发送异步异常给指定线程的。
    :param tid:表示线程的id
    :param exc_type:表示发送的异常类型
    :return:
    '''
    tid = ctypes.c_long(tid)

    # 判断exc_type该异常类型是否为一个类，如果不是就用type转换为类对象
    if not inspect.isclass(exc_type):
        exc_type = type(exc_type)

    #设置异步异常信号，以停止指定的线程
    #ctypes.py_object(exc_type)：将类型转换为C类型的对象
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,ctypes.py_object(exc_type))

    if res == 0:    #表示线程ID无效
        raise ValueError('invalid thread id')
    elif res != 1:  #表示函数调用失败，由于传入异常参数类型为None，就会引发SystemError异常
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,None)
        raise SystemError("PyThreadState_SetAsyncExc failed")


def stop_thread(thread):
    '''
    用来停止一个线程的，接收一个线程对象作为参数
    并使用_async_raise函数来抛出SystemExit异常来停止线程的执行
    SystemExit：内置的一个异常类，当系统接收到退出信号时，就会抛出
                这个异常。通常用于正常的终止程序的执行。
    :param thread:一个线程对象
    :return:
    '''
    _async_raise(thread.ident,SystemExit)



